package edu.xlh.travel.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.sun.org.apache.bcel.internal.generic.NEW;
import edu.xlh.travel.common.GalleryInRedisConstant;
import edu.xlh.travel.common.Result;
import edu.xlh.travel.dao.HotelDao;

import edu.xlh.travel.elasticsearch.common.EsConstant;
import edu.xlh.travel.elasticsearch.utils.BusinessQueryUtil;
import edu.xlh.travel.elasticsearch.utils.ElasticsearchUtil;
import edu.xlh.travel.pojo.Hotel;
import edu.xlh.travel.pojo.Scenic;
import edu.xlh.travel.pojo.User;
import edu.xlh.travel.service.HotelService;
import edu.xlh.travel.util.IdWorker;
import edu.xlh.travel.util.PageResult;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpSession;
import javax.transaction.Transactional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

@Service
@Transactional
public class HotelServiceImpl implements HotelService {
    @Autowired
    private HotelDao hotelDao;
    @Autowired
    private IdWorker idWorker;
    @Value("http://${ftp-centos.host}")
    private String ftpCentosIp;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ElasticsearchUtil<Hotel> elasticsearchUtil ;
    @Autowired
    private BusinessQueryUtil<Hotel> businessQueryUtil ;


    @Override
    public String findAllHotel(Model model, Integer start, Integer limit, Integer price, Integer star) {
        List<Sort.Order> sort=new ArrayList<>();
        if (star == 3) {
            sort.add(new Sort.Order(Sort.Direction.ASC,"star"));
        } else if (star == 2) {
            sort.add(new Sort.Order(Sort.Direction.DESC,"star"));
        } else if (price == 3) {
            sort.add(new Sort.Order(Sort.Direction.ASC,"price"));
        } else {
            sort.add(new Sort.Order(Sort.Direction.DESC,"price"));
        }
        Pageable pageable= PageRequest.of(start,limit,Sort.by(sort));
        Specification specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> hotelList = new ArrayList<>();
                hotelList.add(criteriaBuilder.equal(root.get("delFlag"), "0"));
                return criteriaBuilder.and(hotelList.toArray(new Predicate[hotelList.size()]));
            }
        };
        Page<Hotel> page=hotelDao.findAll(specification , pageable);
        model.addAttribute("attrs",page);
        model.addAttribute("number",page.getNumber());//页码
        model.addAttribute("numberOfElements",page.getNumberOfElements());
        model.addAttribute("size",page.getSize());
        model.addAttribute("totalElements",page.getTotalElements());
        model.addAttribute("totalPages",page.getTotalPages());
        model.addAttribute("first",page.isFirst());
        model.addAttribute("last",page.isLast());
        model.addAttribute("price",price);
        model.addAttribute("star",star);
        return "page/hotels";
    }

    @Override
    public String findById(Model model, String id) {
        Hotel hotel = hotelDao.findById(id).get();
        model.addAttribute("oneAttr" , hotel);
        return "page/hotelDetail";
    }

    @Override
    public String findAll(Model model, Integer start, Integer limit, String search_key) {
        start = start < 0 ? 0 : start;
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(start, limit, sort);
        Specification specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> scenics = new ArrayList<>();
                if (StringUtils.isNotBlank(search_key)) {
                    scenics.add(criteriaBuilder.like(root.get("name"), "%" + search_key + "%"));
                }
                return criteriaBuilder.and(scenics.toArray(new Predicate[scenics.size()]));
            }
        };
        Page<Scenic> page = hotelDao.findAll(specification, pageable);
        model.addAttribute("attrs", page);
        model.addAttribute("number", page.getNumber());
        model.addAttribute("numberOfElements", page.getNumberOfElements());
        model.addAttribute("size", page.getSize());
        model.addAttribute("totalElements", page.getTotalElements());
        model.addAttribute("totalPages", page.getTotalPages());
        model.addAttribute("first", page.isFirst());
        model.addAttribute("last", page.isLast());
        return "page/hotels";
    }

    @Override
    public Result findAll(int page  , int size , HttpSession session) {
        User user = (User)session.getAttribute("admin");
        if (user == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        Specification specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> hotelList = new ArrayList<>();
                hotelList.add(criteriaBuilder.equal(root.get("delFlag"), "0"));
                return criteriaBuilder.and(hotelList.toArray(new Predicate[hotelList.size()]));
            }
        };
        Pageable pageable= PageRequest.of(page-1,size);
        //Sort sort = Sort.by(Sort.Direction.DESC, "startDate");
        Page<Hotel> hotelListPage  = hotelDao.findAll(specification , pageable);
        if (hotelListPage!=null) {
            return new Result(0 , "酒店分页数据获取成功" , new PageResult<Hotel>(hotelListPage.getTotalElements(), hotelListPage.getContent()));
        }
        return new Result(201 , "返回酒店列表失败");
    }

    @Override
    public Hotel findByHotelId(String scenicId) {
        return hotelDao.findById(scenicId).get();
    }

    @Override
    public Result edit(String id, Hotel hotel , HttpSession session) {
        User user = (User)session.getAttribute("admin");
        if (user == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        hotel.setId(id);
        try {
            hotelDao.updateHotelByHotelId(hotel);
        } catch (Exception e) {
            return new Result(201 , "酒店数据修改失败");
        }
        return new Result(200 , "酒店数据修改成功");
    }

    @Override
    public Result editMiaoShu(String id, Hotel hotel , HttpSession session) {
        User user = (User)session.getAttribute("admin");
        if (user == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        hotel.setId(id);
        try {
            hotelDao.editMiaoShu(hotel);
        } catch (Exception e) {
            return new Result(201 , "酒店数据修改失败");
        }
        return new Result(200 , "酒店数据修改成功");
    }

    @Override
    public Result deleteById(String id, HashMap hashMap, HttpSession session) {
        User user = (User)session.getAttribute("admin");
        if (user == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        String hotelId = (String) hashMap.get("id");
        if (id.equals(hotelId)) {
            try {
                hotelDao.updateScenicDelFlagByScenicId(hotelId , "1");
                elasticsearchUtil.deleteRequest(EsConstant.E_HOTEL , hotelId);
            } catch (Exception e) {
                return new Result(201 , "id为"+hotelId+"的酒店记录"+"删除失败");
            }
        } else {
            return new Result(202 , "id为"+hotelId+"的酒店id有问题");
        }
        return new Result(200 , "id为"+hotelId+"的酒店记录"+"删除成功");
    }

    @Override
    public Result addHotel(Hotel hotel, HttpSession session) {
        User user = (User)session.getAttribute("admin");
        if (user == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        hotel.setId(idWorker.nextId() + "");
        String image = hotel.getImg();
        hotel.setImg(ftpCentosIp+"/"+image);
        hotel.setDelFlag("0");
        try {
             hotelDao.save(hotel);
            elasticsearchUtil.addDocument(EsConstant.E_HOTEL ,  hotel.getId() , hotel);
            redisTemplate.boundSetOps(GalleryInRedisConstant.Gallery_DB_RESOURCES).add(image);
        } catch(Exception  e) {
            return new Result(202, "酒店数据添加失败");
        }
        return new Result(200 , "酒店数据添加成功");
    }

    @Override
    public Result batchDelete(JSONArray jsonArray, HttpSession session) {
        List<Hotel> hotelList = JSON.parseArray(jsonArray.toJSONString() , Hotel.class);
        try {
            hotelList.stream().iterator().forEachRemaining(hotel -> {
                hotelDao.updateScenicDelFlagByScenicId(hotel.getId() , "1");
                try {
                    elasticsearchUtil.deleteRequest(EsConstant.E_HOTEL , hotel.getId());
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("es删除异常");
                }
            });
        }catch (Exception e) {
            return new Result(201);
        }
        return new Result(200);
    }

    @Override
    public Result QueryHotelByCondition(Integer page, Integer limit, Hotel hotel, HttpSession session) throws IOException {
        User userFromSession = (User)session.getAttribute("admin");
        if (userFromSession == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        //es获取数据
        List<Hotel> hotelList = businessQueryUtil.hotelQueryBuilders(hotel, page, limit);
        if (hotelList!=null && hotelList.size() > 0) {
            return new Result(0 , "酒店分页数据获取成功" , new PageResult<Hotel>((long)hotelList.size(), hotelList));
        }
        Specification specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> hotelList = new ArrayList<>();
                if (StringUtils.isNotEmpty(hotel.getName())) {
                    hotelList.add(criteriaBuilder.like(root.get("name") , "%" + hotel.getName() + "%"));
                }
                if (StringUtils.isNotEmpty(hotel.getAddr())) {
                    hotelList.add(criteriaBuilder.like(root.get("addr") , "%" + hotel.getAddr() + "%"));
                }
                if (hotel.getPrice() != null) {
                    hotelList.add(criteriaBuilder.between(root.get("price") ,  hotel.getPrice() - 10 , hotel.getPrice() + 10));
                }
                if (hotel.getBedNum() != null) {
                    hotelList.add(criteriaBuilder.equal(root.get("bedNum") , hotel.getBedNum()));
                }
                if (hotel.getStock() != null) {
                    hotelList.add(criteriaBuilder.between(root.get("stock") , hotel.getStock() - 10 , hotel.getStock() + 10));
                }
                    hotelList.add(criteriaBuilder.equal(root.get("delFlag") , "0"));
                return criteriaBuilder.and(hotelList.toArray(new Predicate[hotelList.size()]));
            }
        };
        Pageable pageable= PageRequest.of(page-1,limit);
        Page<Hotel> hotelListPage  = hotelDao.findAll(specification , pageable);
        if (hotelListPage!=null) {
            return new Result(0 , "酒店分页数据获取成功" , new PageResult<Hotel>(hotelListPage.getTotalElements(), hotelListPage.getContent()));
        }
        return new Result(201 , "酒店列表失败");
    }

}
